package cn.tt.tuantuanerp.tuantuanerp.product.webapi.service.impl;


import cn.tt.tuantuanerp.tuantuanerp.comment.ex.ReportSystemException;
import cn.tt.tuantuanerp.tuantuanerp.comment.ex.ServiceException;
import cn.tt.tuantuanerp.tuantuanerp.comment.pojo.dto.productModule.SkuAddNewBasicDTO;
import cn.tt.tuantuanerp.tuantuanerp.comment.pojo.dto.productModule.SkuAddNewDTO;
import cn.tt.tuantuanerp.tuantuanerp.comment.pojo.dto.productModule.SkuUpdateDTO;
import cn.tt.tuantuanerp.tuantuanerp.comment.pojo.entity.Sku;
import cn.tt.tuantuanerp.tuantuanerp.comment.pojo.entity.SkuCheckInfo;
import cn.tt.tuantuanerp.tuantuanerp.comment.pojo.entity.SkuLog;
import cn.tt.tuantuanerp.tuantuanerp.comment.pojo.entity.SkuOrderInfo;
import cn.tt.tuantuanerp.tuantuanerp.comment.pojo.entity.SkuPurchaseInfo;
import cn.tt.tuantuanerp.tuantuanerp.comment.pojo.vo.*;
import cn.tt.tuantuanerp.tuantuanerp.comment.security.LoginPrincipal;
import cn.tt.tuantuanerp.tuantuanerp.comment.utils.Bean;
import cn.tt.tuantuanerp.tuantuanerp.comment.web.ServiceCode;
import cn.tt.tuantuanerp.tuantuanerp.orderservice.ISkuInOrderService;
import cn.tt.tuantuanerp.tuantuanerp.product.service.ISkuService;
import cn.tt.tuantuanerp.tuantuanerp.product.webapi.mapper.SkuLogMapper;
import cn.tt.tuantuanerp.tuantuanerp.product.webapi.mapper.SkuMapper;
import cn.tt.tuantuanerp.tuantuanerp.product.webapi.utils.SkuApi;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;

/**
 * sku service 的实现
 *
 * @author dadadawei
 */
@Slf4j
@Service
@DubboService
public class SkuServiceImpl implements ISkuService {

    @Autowired
    private SkuMapper skuMapper;
    @Autowired
    private SkuLogMapper skuLogMapper;

    @DubboReference
    private ISkuInOrderService dubboSkuInOrderService;

    @Override
    public void addNew(SkuAddNewDTO skuAddNewDTO, LoginPrincipal loginPrincipal) {
        log.debug("开始执行新增sku操作,数据:{},操作人:{}", skuAddNewDTO, loginPrincipal.getUsername());
        //TODO 一系列检查
        // 检查xxxx
        checkSkuId(skuAddNewDTO.getSkuId());
        log.debug("检查完成,数据无异常,开始写入sku");
        //获取到一个初始化完成的sku
        Sku sku = getDefaultSku();
        //将前端获取的数据赋值给sku
        BeanUtils.copyProperties(skuAddNewDTO, sku, Bean.getNullPropertyNames(skuAddNewDTO));
        //将sku写入到数据库
        sku.setCreatePerson(loginPrincipal.getUsername());
        sku.setCreatePersonId(loginPrincipal.getId());
        add(sku);
        //  日志
        String message = loginPrincipal.getUsername() + "【" + loginPrincipal.getPhone() + "】创建了sku。";
        doLog(message, sku.getSkuId(), loginPrincipal);
    }

    /**
     * 添加新sku 的业务方法
     *
     * @param skuAddNewBasicDTO 新sku 的数据封装
     */
    @Override
    public void addNew(SkuAddNewBasicDTO skuAddNewBasicDTO, LoginPrincipal loginPrincipal) {
        log.debug("开始处理添加sku业务,参数为:{},操作人为:{}", skuAddNewBasicDTO, loginPrincipal.getUsername());
        //TODO 一系列检查
        checkSkuId(skuAddNewBasicDTO.getSkuId());
        log.debug("检查完成,数据无异常,开始写入sku");
        //获取到一个初始化完成的sku
        Sku sku = getDefaultSku();
        //将前端获取的数据赋值给sku
        BeanUtils.copyProperties(skuAddNewBasicDTO, sku, Bean.getNullPropertyNames(skuAddNewBasicDTO));
        //将sku写入到数据库
        sku.setCreatePerson(loginPrincipal.getUsername());
        sku.setCreatePersonId(loginPrincipal.getId());
        add(sku);
        // 日志
        String message = loginPrincipal.getUsername() + "【" + loginPrincipal.getPhone() + "】创建了sku。";
        doLog(message, sku.getSkuId(), loginPrincipal);
    }

    @Override
    public void updateById(SkuUpdateDTO skuUpdateDTO, LoginPrincipal loginPrincipal) {
        log.debug(skuUpdateDTO.toString());
        log.debug(loginPrincipal.toString());

        log.debug("开始处理更新sku业务,参数为:{},操作人为:{}", skuUpdateDTO, loginPrincipal.getUsername());
        //TODO 一系列检查
        //检查该sku是否存在,且未被标记为删除
        Integer isDelete = skuMapper.getIsDeleteById(skuUpdateDTO.getSkuId());
        //如果该商品不存在或者被删除,则抛出异常
        if (isDelete == null || isDelete == 1) {
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "更新失败,该商品不存在,...");
        }
        String[] messages = skuUpdateDTO.getNotes();
        if (messages == null) {
            throw new ServiceException(ServiceCode.ERR_BAD_REQUEST, "您未修改任何信息,请检查后重试!");
        }
        //开始写入数据
        Sku sku = new Sku();
        BeanUtils.copyProperties(skuUpdateDTO, sku, Bean.getNullPropertyNames(skuUpdateDTO));
        int i = skuMapper.updateById(sku);
        if (i != 1) {
            throw new ServiceException(ServiceCode.ERR_UNKNOWN, "服务器发生了未知错误,请稍后再试...");
        }
        //TODO 记录日志

        for (String message : messages) {
            doLog(message, sku.getSkuId(), loginPrincipal);
        }
    }


    @Override
    public void deleteById(Long id, LoginPrincipal loginPrincipal) {
        log.debug("开始处理删除sku业务,id为:{},操作人为:{}", id, loginPrincipal.getUsername());
        //TODO
        SkuDetailsVO detailsById = skuMapper.getDetailsById(id);
        // 检查采购在途数量是否为0
        if (detailsById == null) {
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, "删除失败!该sku不存在");
        }
        if (detailsById.getPurchaseNum() != 0 ||detailsById.getTransitNum()!=0) {
            throw new ServiceException(ServiceCode.ERR_NOT_NULL, "删除失败!该sku有尚未完成的采购单");
        }
        int i = skuMapper.deleteById(id);
        if (i != 1) {
            throw new ServiceException(ServiceCode.ERR_UNKNOWN, "服务器发生了未知错误,请稍后再试...");
        }
        //TODO 记录日志
        String message = loginPrincipal.getUsername() + "【" + loginPrincipal.getPhone() + "】删除了sku。";
        doLog(message, id, loginPrincipal);
    }

    @Override
    public SkuDetailsVO getDetailById(Long id, LoginPrincipal loginPrincipal) {
        log.debug("开始处理查询sku详情业务,id为:{},:{}", id, loginPrincipal.getUsername());
        //
        SkuDetailsVO detailsById = skuMapper.getDetailsById(id);
        if (detailsById == null) {
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, "该sku不存在!");
        }
        return detailsById;
    }

    @Override
    public List<SkuListItemVO> list(int pageIndex, int pageSize, LoginPrincipal loginPrincipal) {
        //log.debug("开始处理查询sku列表业务,操作人为:{}",loginPrincipal.getUsername());
        PageHelper.startPage(pageIndex,pageSize);
        return skuMapper.list();
    }

    @Override
    public SkuForOrderVO getSkuForOrder(Long id, LoginPrincipal loginPrincipal) {
        //log.debug("开始处理查询skuFroOrder业务,操作人为:{},查询参数为:{}",loginPrincipal.getUsername(),id);
        SkuForOrderVO result = skuMapper.getInfoForOrder(id);
        if (result == null) {
            //新增一个临时sku,临时sku数据由第三方api生成
            Sku skuInfoByApi = SkuApi.getSkuInfoByApi(id, getDefaultSku());
            skuInfoByApi.setCreatePerson("System");
            skuInfoByApi.setCreatePersonId(loginPrincipal.getId());
            add(skuInfoByApi);
            //记录日志
            String message = "订单出库,系统自动创建了sku:" + id + ",订单操作人:" + loginPrincipal.getUsername() +
                    "【" + loginPrincipal.getPhone() + "】";
            SkuLog skuLog = new SkuLog();
            skuLog.setSkuId(id);
            skuLog.setMessage(message);
            skuLog.setPrincipalId(loginPrincipal.getId());
            skuLog.setPrincipalName("System");
            skuLog.setGmtCreate(LocalDateTime.now());
            skuLogMapper.addNew(skuLog);
            SkuForOrderVO skuForOrderVO = new SkuForOrderVO();
            BeanUtils.copyProperties(skuInfoByApi,skuForOrderVO);
            return skuForOrderVO;
        }
        return result;
    }

    @Override
    public SkuForCheckVO getSkuFroCheck(Long id, LoginPrincipal loginPrincipal) {
        //log.debug("开始处理查询skuFroCheck业务,操作人为:{},查询参数为:{}",loginPrincipal.getUsername(),id);
        SkuForCheckVO result = skuMapper.getInfoForCheck(id);
        if (result == null) {
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, "该sku不存在!");
        }
        return result;
    }

    @Override
    public Sku getSkuInfoByApiForAddNew(Long skuId) {
        /*Integer isDeleteById = skuMapper.getIsDeleteById(skuId);
        if (isDeleteById != null && isDeleteById == 0) {
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "该sku已存在!");
        }*/
        Sku sku = SkuApi.getSkuInfoByApiForAddNewSku(skuId);
        if (sku == null) {
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, "未找到该sku");
        }
        return sku;
    }

    @Override
    public SkuListItemVO getListItemById(Long skuId) {
        return skuMapper.getListItemById(skuId);
    }

    @Override
    public SkuForPurchaseVO getSkuFroPurchase(Long id, LoginPrincipal loginPrincipal) {
        //log.debug("开始处理查询skuFroPurchase业务,操作人为:{},查询参数为:{}",loginPrincipal.getUsername(),id);
        SkuForPurchaseVO result = skuMapper.getForPurchase(id);
        if (result == null) {
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, "该sku不存在!");
        }
        return result;
    }
    @Override
    public void setPurchaseInfoBat(String purchaseId, SkuPurchaseInfo[] skuPurchaseInfo, LoginPrincipal loginPrincipal) {
        log.debug("开始处理设置采购在途数量和上次采购价,操作人:{}", loginPrincipal.getUsername());

        //TODO 一系列检查

        Integer transitNum1 = skuPurchaseInfo[0].getTransitNum();
        //如果采购在途小于0,则为签收时调用
        if (transitNum1 < 0) {
            //修改在途量,增加库存,修改最新入库时间,修改上次采购价,修改仓库成本价
            setInfoAfter(purchaseId, skuPurchaseInfo, loginPrincipal);
        } else {
            //修改在途量
            setInfoBefore(purchaseId, skuPurchaseInfo, loginPrincipal);
        }

    }

    @Override
    public void setCheckInfoBat(Long checkWarehouseId, SkuCheckInfo[] skuCheckInfo, LoginPrincipal loginPrincipal) {
        log.debug("开始处理盘点后数据,操作人:{}", loginPrincipal.getUsername());

        //TODO 一系列检查

        //更新数据
        int rows = 0;
        for (SkuCheckInfo checkInfo : skuCheckInfo) {
            log.debug("需要更改的盘点数据:{}", checkInfo);
            Sku sku = new Sku();
            Long skuId = checkInfo.getSkuId();
            Integer goodsStock = checkInfo.getCheckNumberResult();
            sku.setSkuId(skuId);
            sku.setGoodsStock(goodsStock);

            int row = skuMapper.updateById(sku);
            if (row != 1) {
                throw new ServiceException(ServiceCode.ERR_UNKNOWN, "服务器发生了未知错误,请稍后再试...");
            }
            rows += row;
            // 记录日志
            String message = loginPrincipal.getUsername() + "【" + loginPrincipal.getPhone() +
                    "】审核通过了盘点单,盘点前商品数量:" + checkInfo.getExpectNumber() + "，盘点后商品数量:" + checkInfo.getCheckNumber() +
                    "盘点批次号:" + checkWarehouseId;
            doLog(message, skuId, loginPrincipal);
        }
        if (rows != skuCheckInfo.length) {
            throw new ServiceException(ServiceCode.ERR_UNKNOWN, "服务器发生了未知错误,请稍后再试...");
        }

    }

    @Override
    public SkuOrderInfo[] setOrderInfoBat(String oderId, SkuOrderInfo[] skuOrderInfos, LoginPrincipal loginPrincipal) {
        //开始执行收到订单,修改数据操作
        //TODO  一系列检查

        //批处理受影响的行数
        int rows = 0;
        for (SkuOrderInfo skuOrderInfo : skuOrderInfos) {
            Long skuId = skuOrderInfo.getSkuId();
            // 根据id查售价,赋值给skuOrderInfo
            skuOrderInfo.setWareCostPrice(skuMapper.getWareCostPrice(skuId));
            Integer goodsStock = skuOrderInfo.getGoodsStock();
            Sku sku = new Sku();
            sku.setSkuId(skuId);
            //减少库存
            sku.setGoodsStock((-1) * goodsStock);
            //设置最新出库时间
            sku.setLatestReleaseTime(LocalDateTime.now());
            //受影响的行数
            int row = skuMapper.updateById(sku);
            if (row != 1) {
                throw new ServiceException(ServiceCode.ERR_UNKNOWN, "服务器发生了未知错误,请稍后再试...");
            }
            rows += row;
            // 记录日志
            String message = "订单出库,操作人:" + loginPrincipal.getUsername() + "【" + loginPrincipal.getPhone() +
                    "】,出库数量:" + goodsStock;
            doLog(message, skuId, loginPrincipal);
        }
        if (rows != skuOrderInfos.length) {
            throw new ServiceException(ServiceCode.ERR_UNKNOWN, "服务器发生了未知错误,请稍后再试...");
        }
        return skuOrderInfos;
    }

    /**
     * 定时任务,计算销量
     */
    @Override
    public void doCompute() {
        List<SkuSalesVO> skus = dubboSkuInOrderService.changeSales();
        if (skus == null) {
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,"暂无销售数据");
        }

        System.out.println("远程调用得到"+skus.size()+"条数据");
        int i = 0;
        for (SkuSalesVO skuSalesVO : skus) {
            System.out.println("远程调用得到数据:"+skuSalesVO);
            Sku sku = new Sku();
            sku.setSkuId(skuSalesVO.getSkuId());
            //计算预测日销量公式: 昨天*30% 7天*40%+30天*20%+90天*10%
            Integer sales1 = skuSalesVO.getSales1();
            if (sales1 == null) {
                sales1 = 0;
            }
            Integer sales7 = skuSalesVO.getSales7();
            if (sales7 == null) {
                sales7 = 0;
            }
            Integer sales30 = skuSalesVO.getSales30();
            if (sales30 == null) {
                sales30 = 0;
            }
            Integer sales90 = skuSalesVO.getSales90();
            if (sales90 == null) {
                sales90 = 0;
            }
            BeanUtils.copyProperties(skuSalesVO,sku);
            sku.setForecastDailySales((int) (sales1 *0.3+ sales7 *0.4+ sales30 *0.2+ sales90 *0.1));
            if (sku.getForecastDailySales()==0){
                sku.setForecastDailySales(1);
            }
            i += skuMapper.updateById(sku);
            //计算当前可售天数
            skuMapper.updateCurrentAvailableDays(skuSalesVO.getSkuId());
        }
       /* if (i != skus.size()){
            log.error("报表系统运行出现未知错误");
            throw new ReportSystemException("报表系统运行出现未知错误!");
        }*/
        //TODO 其他计算

    }

    @Override
    public List<SkuForPurchaseVO> listStockOut(int pageIndex,int pageSize) {
        PageHelper.startPage(pageIndex,pageSize);
        return skuMapper.getStockOutDetails();
    }

    @Override
    public int count() {
        return skuMapper.count();
    }

    @Override
    public List<SkuListItemVO> list() {
        return skuMapper.list();
    }

    @Override
    public List<SkuDetailsVO> searchSku() {

        return skuMapper.searchSku();
    }

    /**
     * 查询这个sku是否已存在
     *
     * @param skuId skuId
     */
    private void checkSkuId(Long skuId) {
        //根据id查询，查询是否该sku已存在
        Integer isDelete = skuMapper.getIsDeleteById(skuId);
        //如果该商品存在并且未被删除,则抛出异常
        if (isDelete != null) {
            if (isDelete == 0) {
                throw new ServiceException(ServiceCode.ERR_CONFLICT, "该商品已存在,请勿重复添加...");
            }
            //如果该商品已被删除
            if (isDelete == 1) {
                //删除该数据,如果没有删除成功,则向浏览器抛出一个未知异常
                int row = skuMapper.deleteById(skuId);
                if (row != 1) {
                    throw new ServiceException(ServiceCode.ERR_UNKNOWN, "服务器发生了未知错误,请稍后再试...");
                }
            }
        }
    }

    /**
     * 为添加的sku进行初始化
     *
     * @return 需要添加的实例对象
     */
    private Sku getDefaultSku() {
        Sku sku = new Sku();
        //设置sku状态
        sku.setSkuStatus(0);
        sku.setGoodsMass(0);
        sku.setLength(0);
        sku.setWidth(0);
        sku.setHeight(0);
        sku.setGoodsShelfLife(999999999);
        //设置默认未删除状态
        sku.setIsDelete(0);
        sku.setCreateTime(LocalDateTime.now());
        // 设置采购天数
        sku.setPurchaseDays(0);
        sku.setWareCostPrice(new BigDecimal("0.00"));
        sku.setGoodsStock(0);
        sku.setWarningStock(0);
        sku.setProductAlertDays(0);
        sku.setTransitNum(0);
        sku.setPurchaseNum(0);
        sku.setWareAlertDays(0);
        sku.setForecastDailySales(0);
        sku.setSales7(0);
        sku.setSales30(0);
        sku.setSales90(0);
        return sku;
    }

    /**
     * 写入到数据库
     *
     * @param sku 最终数据
     */
    private void add(Sku sku) {
        System.out.println("sku = " + sku);
        int i = skuMapper.addNew(sku);
        if (i != 1) {
            throw new ServiceException(ServiceCode.ERR_UNKNOWN, "服务器发生了未知错误,请稍后再试...");
        }
    }

    /**
     * 修改在途量,增加库存,修改最新入库时间修改上次采购价
     *
     * @param skuPurchaseInfo 数据
     */
    private void setInfoAfter(String purchaseId, SkuPurchaseInfo[] skuPurchaseInfo, LoginPrincipal loginPrincipal) {
        log.debug("减少途量,增加库存,修改上次采购价...");
        int rows = 0;
        for (SkuPurchaseInfo purchaseInfo : skuPurchaseInfo) {
            log.debug("需要更改的采购数据:{}", purchaseInfo);
            Long skuId = purchaseInfo.getSkuId();
            BigDecimal newPrice = purchaseInfo.getLastPurchasePrice();
            Integer purchaseDays = purchaseInfo.getPurchaseDays();
            int transitNum = purchaseInfo.getTransitNum();

            Sku sku = new Sku();
            sku.setSkuId(skuId);
            //设置上次采购价
            sku.setLastPurchasePrice(newPrice);
            //减少采购在途量
            sku.setTransitNum(transitNum);
            //设置最新入库时间
            sku.setLatestEntryTime(LocalDateTime.now());
            //增加商品库存
            sku.setGoodsStock((-1) * transitNum);
            //设置仓库成本价
            SkuDetailsVO detailsById = skuMapper.getDetailsById(skuId);
            //当前的库存
            int goodsStock = detailsById.getGoodsStock();
            //当前成本价
            BigDecimal wareCostPrice = detailsById.getWareCostPrice();
            //新的单价  计算公式:((原单价*原数量)+(现单价*现数量)) / (现数量*原数量)
            BigDecimal newCostPrice = (newPrice.multiply(new BigDecimal(transitNum)).add(wareCostPrice.multiply(new BigDecimal(goodsStock))))
                    .divide(new BigDecimal(goodsStock + transitNum), 2, RoundingMode.HALF_UP);
            sku.setWareCostPrice(newCostPrice);
            //修改采购天数
            sku.setPurchaseDays(purchaseDays);
            int row = skuMapper.updateById(sku);
            if (row != 1) {
                throw new ServiceException(ServiceCode.ERR_UNKNOWN, "服务器发生了未知错误,请稍后再试...");
            }
            rows += row;
            // 日志
            String message = "采购入库,操作人:" + loginPrincipal.getUsername() + "【" + loginPrincipal.getPhone() +
                    "】,采购入库数量:" + (-1) * transitNum + ",采购单号:" + purchaseId;
            doLog(message, skuId, loginPrincipal);

            //修改当前可售天数
            skuMapper.updateCurrentAvailableDays(skuId);
        }
        if (rows != skuPurchaseInfo.length) {
            throw new ServiceException(ServiceCode.ERR_UNKNOWN, "服务器发生了未知错误,请稍后再试...");
        }
    }

    /**
     * 设置采购在途数量
     */
    private void setInfoBefore(String purchaseId, SkuPurchaseInfo[] skuPurchaseInfo, LoginPrincipal loginPrincipal) {
        log.debug("设置采购在途数量...");
        int rows = 0;
        for (SkuPurchaseInfo purchaseInfo : skuPurchaseInfo) {
            log.debug("需要更改的采购数据:{}", purchaseInfo);
            Sku sku = new Sku();
            sku.setSkuId(purchaseInfo.getSkuId());
            //增加采购在途量
            sku.setTransitNum(purchaseInfo.getTransitNum());
            int row = skuMapper.updateById(sku);
            if (row != 1) {
                throw new ServiceException(ServiceCode.ERR_UNKNOWN, "服务器发生了未知错误,请稍后再试...");
            }
            rows += row;
            // 日志
            String message = "开始采购:" + loginPrincipal.getUsername() + "【" + loginPrincipal.getPhone() +
                    "】,采购数量:" + purchaseInfo.getTransitNum() + ",采购单号:" + purchaseId;
            doLog(message, purchaseInfo.getSkuId(), loginPrincipal);
        }
        if (rows != skuPurchaseInfo.length) {
            throw new ServiceException(ServiceCode.ERR_UNKNOWN, "服务器发生了未知错误,请稍后再试...");
        }

    }

    private void doLog(String message ,Long id, LoginPrincipal loginPrincipal) {
        SkuLog skuLog = new SkuLog();
        skuLog.setSkuId(id);
        skuLog.setMessage(message);
        skuLog.setPrincipalId(loginPrincipal.getId());
        skuLog.setPrincipalName(loginPrincipal.getUsername());
        skuLog.setGmtCreate(LocalDateTime.now());
        skuLogMapper.addNew(skuLog);
    }


}
